home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 028a / unzup41e.zip / UNZIP.C < prev    next >
C/C++ Source or Header  |  1991-05-14  |  60KB  |  1,565 lines

  1. /*---------------------------------------------------------------------------
  2.  
  3.   unzip.c
  4.  
  5.   This is nearly a complete rewrite of unzip.c, mainly to allow access to
  6.   zipfiles via the central directory (and hence to the OS bytes, so we can
  7.   make intelligent decisions about what to do with the extracted files).
  8.   Based on unzip.c 3.15+ and zipinfo.c 0.90.
  9.  
  10.   ---------------------------------------------------------------------------
  11.  
  12.   To compile (partial instructions):
  13.  
  14.      under Unix (cc):  make <system name>
  15.        (type "make" for list of valid names, or read Makefile for details)
  16.  
  17.      under MS-DOS (TurboC):  make -fMAKEFILE.DOS  for command line compiles
  18.        (or use the integrated environment and the included files TCCONFIG.TC
  19.         and UNZIP.PRJ.  Tweak for your environment.)
  20.  
  21.      under MS-DOS (MSC):  make MAKEFILE.DOS
  22.        (or use Makefile if you have MSC 6.0:  "nmake msc_dos")
  23.  
  24.      under OS/2 (MSC):  make MAKEFILE.DOS   (edit appropriately)
  25.        (or use Makefile if you have MSC 6.0:  "nmake msc_os2")
  26.  
  27.      under Atari OS:  Any Day Now.
  28.  
  29.      under VMS:  DEFINE LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB   (see VMSNOTES)
  30.                  CC UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  31.                  LINK UNZIP,FILE_IO,MAPNAME,MATCH,...,UNSHRINK
  32.                  UNZIP :== $DISKNAME:[DIRECTORY]UNZIP.EXE
  33.  
  34.      under Macintosh OS:   Double click on unzip.mac.  Press <Command>-M
  35.  
  36.   ---------------------------------------------------------------------------
  37.  
  38.   Version:  unzip41.arc/unzip41.tar.Z for Unix, VMS, OS/2, MS-DOS & Mac
  39.   Source:   wsmr-simtel20.army.mil (192.88.110.20) in pd1:[misc.unix]
  40.             wuarchive.wustl.edu (128.252.135.4) in /mirrors/misc/unix
  41.   Source:   wsmr-simtel20.army.mil (26.2.0.74) in pd1:[misc.unix]
  42.  
  43.   ---------------------------------------------------------------------------
  44.  
  45.   Copyright, originally from version 1.2 (?):
  46.  
  47.      * Copyright 1989 Samuel H. Smith;  All rights reserved
  48.      *
  49.      * Do not distribute modified versions without my permission.
  50.      * Do not remove or alter this notice or any other copyright notice.
  51.      * If you use this in your own program you must distribute source code.
  52.      * Do not use any of this in a commercial product.
  53.  
  54.   ---------------------------------------------------------------------------
  55.  
  56.   Comments from unzip.c, version 3.11:
  57.  
  58.      * UnZip - A simple zipfile extract utility
  59.      *
  60.      * Compile-time definitions:
  61.      * See the Makefile for details, explanations, and all the current
  62.      * system makerules.
  63.      *
  64.      * If you have to add a new one for YOUR system, please forward the new
  65.      * Makefile context diff to kirsch%maxemail@uunet.uu.net for distribution.
  66.      * Be SURE to give FULL details on your system (hardware, OS, versions,
  67.      * processor, whatever) that made it unique.
  68.      *
  69.      * REVISION HISTORY : See History.41 (or whatever current version is)
  70.  
  71.   To join Info-ZIP, send a message to Info-ZIP-Request@WSMR-Simtel20.Army.Mil
  72.  
  73.   ---------------------------------------------------------------------------*/
  74.  
  75.  
  76.  
  77.  
  78.  
  79. #include "unzip.h"              /* includes, defines, and macros */
  80.  
  81. #define VERSION  "v4.1 of 5-13-91"
  82. #define PAKFIX   /* temporary solution to PAK-created zipfiles */
  83.  
  84.  
  85.  
  86.  
  87.  
  88. /**********************/
  89. /*  Global Variables */
  90. /**********************/
  91.  
  92. int tflag;              /* -t: test */
  93. int vflag;              /* -v: view directory (only used in unzip.c) */
  94. int cflag;              /* -c: output to stdout */
  95. int aflag;              /* -a: do ascii to ebcdic translation OR CR-LF */
  96.                         /*     to CR or LF conversion of extracted files */
  97. int dflag;              /* -d: create containing directories */
  98. int Uflag;              /* -U: leave filenames in upper or mixed case */
  99. int V_flag;             /* -V: don't strip VMS version numbers */
  100. int quietflg;           /* -q: produce a lot less output */
  101. int do_all;             /* -o: OK to overwrite files without prompting */
  102. int zflag;              /* -z: Display only the archive comment */
  103.  
  104. int lcflag;             /* convert filename to lowercase */
  105. unsigned f_attr;        /* file attributes (permissions) */
  106. longint csize;          /* used by list_files(), ReadByte(): must be signed */
  107. longint ucsize;         /* used by list_files(), unReduce(), unImplode() */
  108.  
  109. /*---------------------------------------------------------------------------
  110.     unShrink/unReduce/unImplode working storage:
  111.   ---------------------------------------------------------------------------*/
  112.  
  113. /* prefix_of (for unShrink) is biggest storage area, esp. on Crays...space */
  114. /*  is shared by lit_nodes (unImplode) and followers (unReduce) */
  115.  
  116. short prefix_of[HSIZE + 1];     /* (8193 * sizeof(short)) */
  117. #ifdef MACOS
  118. byte *suffix_of;
  119. byte *stack;
  120. #else
  121. byte suffix_of[HSIZE + 1];      /* also s-f length_nodes (smaller) */
  122. byte stack[HSIZE + 1];          /* also s-f distance_nodes (smaller) */
  123. #endif
  124.  
  125. ULONG crc32val;
  126.  
  127. UWORD mask_bits[] =
  128. {0, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
  129.     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff};
  130.  
  131. /*---------------------------------------------------------------------------
  132.     Input file variables:
  133.   ---------------------------------------------------------------------------*/
  134.  
  135. byte *inbuf, *inptr;    /* input buffer (any size is legal) and pointer */
  136. int incnt;
  137.  
  138. UWORD bitbuf;
  139. int bits_left;
  140. boolean zipeof;
  141.  
  142. int zipfd;                      /* zipfile file handle */
  143. char zipfn[FILNAMSIZ];
  144.  
  145. local_file_header lrec;
  146. struct stat statbuf;            /* used by main(), mapped_name() */
  147.  
  148. longint cur_zipfile_bufstart;   /* extract_or_test_files, readbuf, ReadByte */
  149.  
  150. /*---------------------------------------------------------------------------
  151.     Output stream variables:
  152.   ---------------------------------------------------------------------------*/
  153.  
  154. byte *outbuf;                   /* buffer for rle look-back */
  155. byte *outptr;
  156. byte *outout;                   /* scratch pad for ASCII-native trans */
  157. longint outpos;                 /* absolute position in outfile */
  158. int outcnt;                     /* current position in outbuf */
  159.  
  160. int outfd;
  161. char filename[FILNAMSIZ];
  162.  
  163. /*---------------------------------------------------------------------------
  164.     unzip.c static global variables (visible only within this file):
  165.   ---------------------------------------------------------------------------*/
  166.  
  167. static char *fnames[2] =
  168. {"*", NULL};                    /* default filenames vector */
  169. static char **fnv = &fnames[0];
  170. static char sig[5];
  171. static byte *hold;
  172. static int process_all_files;
  173. static longint ziplen;
  174. static UWORD hostnum;
  175. static UWORD methnum;
  176. /* static UWORD extnum; */
  177. static central_directory_file_header crec;
  178. static end_central_dir_record ecrec;
  179.  
  180. /*---------------------------------------------------------------------------
  181.     unzip.c repeated error messages (we use all of these at least twice ==>
  182.     worth it to centralize to keep executable small):
  183.   ---------------------------------------------------------------------------*/
  184.  
  185. static char *CryptMsg =
  186.   "%s:  encrypted (can't do yet)--skipping.\n";
  187. static char *FilNamMsg =
  188.   "\n%s:  bad filename length (%s)\n";
  189. static char *ExtFieldMsg =
  190.   "\n%s:  bad extra field length (%s)\n";
  191. static char *OffsetMsg =
  192.   "\n%s:  bad zipfile offset (%s)\n";
  193. static char *EndSigMsg =
  194.   "\nwarning:  didn't find end-of-central-dir signature at end of central dir.\n";
  195. static char *CentSigMsg =
  196.   "\nerror:  expected central file header signature not found (file #%u).\n";
  197. static char *ReportMsg =
  198.   "        (please report to info-zip@wsmr-simtel20.army.mil)\n";
  199.  
  200. /* (original) Bill Davidsen version */
  201. #define QCOND    (!quietflg)    /* -xq[q] kill "extracting: ..." msgs */
  202. #define QCOND2   (which_hdr)    /* file comments with -v, -vq, -vqq */
  203.  
  204.  
  205.  
  206.  
  207. /*****************/
  208. /*  Main program */
  209. /*****************/
  210.  
  211. main(argc, argv)        /* return PK-type error code (except under VMS) */
  212. int argc;
  213. char *argv[];
  214. {
  215.     char *s;
  216.     int c, print_usage=TRUE;
  217.  
  218.  
  219.  
  220. #ifdef MACOS
  221. #ifdef THINK_C
  222.     #include <console.h>
  223.     #include <StdFilePkg.h>
  224.     typedef struct sf_node {        /* node in a true shannon-fano tree */
  225.         UWORD left;                 /* 0 means leaf node */
  226.         UWORD right;                /*   or value if leaf node */
  227.     } sf_node;
  228.     static char *argstr[30], args[30*64];
  229.  
  230.     extern sf_node *lit_nodes, *length_nodes, *distance_nodes;
  231.  
  232.     Point   p;
  233.     SFTypeList  sfT;
  234.     int a;
  235.     EventRecord theEvent;
  236.     short   eMask;
  237.     SFReply  fileRep;
  238.  
  239.     suffix_of = (byte *)calloc(HSIZE+1, sizeof(byte));
  240.     stack = (byte *)calloc(HSIZE+1, sizeof(byte));
  241.     length_nodes = (sf_node *) suffix_of;  /* 2*LENVALS nodes */
  242.     distance_nodes = (sf_node *) stack;    /* 2*DISTVALS nodes */
  243.    
  244.     for (a=0; a<30; a+=1)
  245.     {
  246.         argstr[a] = &args[a*64];
  247.     }
  248. start:
  249.     tflag = vflag=cflag=aflag=dflag=Uflag=quietflg=lcflag=zflag = 0;
  250.     argc = ccommand(&argv);
  251.     SetPt(&p, 40,40);
  252.  
  253.     SFGetFile(p, "\pSpecify ZIP file:", 0L, -1, sfT, 0L, &fileRep);
  254.     if (!fileRep.good)
  255.         exit(1);
  256.     macfstest(fileRep.vRefNum, true);
  257.     SetMacVol(NULL, fileRep.vRefNum);
  258.     for (a=1; a<argc; a+=1)
  259.     {
  260.         if (argv[a][0] == '-')
  261.         {
  262.             BlockMove(argv[a], argstr[a], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  263.         }
  264.         else
  265.             break;
  266.     }
  267.     PtoCstr((char *)fileRep.fName);
  268.     strcpy(argstr[a], fileRep.fName);
  269.     for (;a<argc; a+=1)
  270.     {
  271.         BlockMove(argv[a], argstr[a+1], (strlen(argv[a])>63) ? 64 : strlen(argv[a])+1);
  272.     }
  273.     argc+=1;
  274.     argv = argstr;
  275.  
  276. #endif /* THINK_C */
  277. #endif /* MACOS */
  278.  
  279. /*---------------------------------------------------------------------------
  280.     Debugging info for checking on structure padding:
  281.   ---------------------------------------------------------------------------*/
  282.  
  283. #ifdef DEBUG_STRUC
  284.     printf("local_file_header size: %X\n",
  285.            sizeof(struct local_file_header));
  286.     printf("local_byte_header size: %X\n",
  287.            sizeof(struct local_byte_header));
  288.     printf("actual size of local headers: %X\n", LREC_SIZE);
  289.  
  290.     printf("central directory header size: %X\n",
  291.            sizeof(struct central_directory_file_header));
  292.     printf("central directory byte header size: %X\n",
  293.            sizeof(struct central_directory_byte_header));
  294.     printf("actual size of central dir headers: %X\n", CREC_SIZE);
  295.  
  296.     printf("end central dir record size: %X\n",
  297.            sizeof(struct end_central_dir_record));
  298.     printf("end central dir byte record size: %X\n",
  299.            sizeof(struct end_central_byte_record));
  300.     printf("actual size of end-central-dir record: %X\n", ECREC_SIZE);
  301. #endif
  302.  
  303. #ifndef KNOW_IT_WORKS  /* define this to save space, if things already work */
  304. #ifndef DOS_OS2        /* already works (no RISCy OS/2's yet...) */
  305. #ifndef NOTINT16       /* whole point is to see if this NEEDS defining */
  306.     {
  307.         int error=0;
  308.         long testsig;
  309.         static char *mach_type[3] = {"big-endian",
  310.           "structure-padding", "big-endian and structure-padding"};
  311.         strcpy((char *)&testsig,"012");
  312.         if (testsig != 0x00323130)
  313.             error = 1;
  314.         if (sizeof(central_directory_file_header) != CREC_SIZE)
  315.             error += 2;
  316.         if (error--)
  317.             fprintf(stderr, "It appears that your machine is %s.  If errors\n\
  318. occur, please try recompiling with \"NOTINT16\" defined (read the\n\
  319. Makefile, or try \"make hp\").\n\n", mach_type[error]);
  320.     }
  321. #endif /* !NOTINT16 */
  322. #endif /* !DOS_OS2 */
  323. #endif /* !KNOW_IT_WORKS */
  324.  
  325. /*---------------------------------------------------------------------------
  326.     Rip through any command-line options lurking about...
  327.   ---------------------------------------------------------------------------*/
  328.  
  329.     while (--argc > 0 && (*++argv)[0] == '-') {
  330.         s = argv[0] + 1;
  331.         while ((c = *s++) != 0) {    /* "!= 0":  prevent Turbo C warning */
  332.             switch (c) {
  333.             case ('x'): /* just ignore -x, -e options (extract) */
  334.             case ('e'):
  335.                 break;
  336.             case ('q'):
  337.                 ++quietflg;
  338.                 break;
  339.             case ('t'):
  340.                 ++tflag;
  341.                 break;
  342.             case ('v'):
  343.                 ++vflag;
  344.                 /* fall thru */
  345.             case ('l'):
  346.                 ++vflag;
  347.                 break;
  348.             case ('p'):
  349.                 ++cflag;
  350. #ifdef NATIVE
  351.                 ++aflag;
  352. #endif
  353.                 quietflg += 2;
  354.                 break;
  355.             case ('c'):
  356.                 ++cflag;
  357. #ifdef NATIVE
  358.                 ++aflag;        /* this is so you can read it on the screen */
  359. #endif
  360.                 break;
  361.             case ('a'):
  362.                 ++aflag;
  363.                 break;
  364. #ifdef VMS
  365.             case ('u'): /* switches converted to l.c. unless quoted */
  366. #endif
  367.             case ('U'): /* "uppercase flag" (i.e., don't convert) */
  368.                 ++Uflag;
  369.                 break;
  370.             case ('V'): /* Version flag:  retain VMS/DEC-20 file versions */
  371.                 ++V_flag;
  372.                 break;
  373.             case ('d'): /* create parent dirs flag */
  374. #ifdef MACOS
  375.                 if (hfsflag == true)
  376. #endif
  377.                 ++dflag;
  378.                 break;
  379.             case ('o'): /* OK to overwrite files without prompting */
  380.                 ++do_all;
  381.                 break;
  382.             case ('z'): /* Display only the archive commentp */
  383.                 ++zflag;
  384.                 break;
  385.             default:
  386.                 if (print_usage) {
  387.                     usage();
  388.                     print_usage = FALSE;
  389.                 }
  390.                 break;
  391.             }
  392.         }
  393.     }
  394.  
  395. /*---------------------------------------------------------------------------
  396.     Make sure we aren't trying to do too many things here.  [This seems like
  397.     kind of a brute-force way to do things; but aside from that, isn't the
  398.     -a option useful when listing the directory (i.e., for reading zipfile
  399.     comments)?  It's a modifier, not an action in and of itself, so perhaps
  400.     it should not be included in the test--certainly, in the case of zipfile
  401.     testing, it can just be ignored.]
  402.   ---------------------------------------------------------------------------*/
  403.  
  404.     if ((tflag && vflag) || (tflag && cflag) || (vflag && cflag) ||
  405.         (tflag && aflag) || (aflag && vflag)) {
  406.         fprintf(stderr, "only one of -t, -c, -a, or -v\n");
  407.         RETURN(10);             /* 10:  bad or illegal parameters specified */
  408.     }
  409.     if (quietflg && zflag)
  410.         quietflg = 0;
  411.     if (argc-- == 0) {
  412.         if (print_usage)
  413.             usage();
  414.         RETURN(10);             /* 10:  bad or illegal parameters specified */
  415.     }
  416. /*---------------------------------------------------------------------------
  417.     Now get the zipfile name from the command line and see if it exists as a
  418.     regular (non-directory) file.  If not, append the ".zip" suffix.  We don't
  419.     immediately check to see if this results in a good name, but we will do so
  420.     later.  In the meantime, see if there are any member filespecs on the com-
  421.     mand line, and if so, set the filename pointer to point at them.
  422.   ---------------------------------------------------------------------------*/
  423.  
  424.     strcpy(zipfn, *argv++);
  425.     if (stat(zipfn, &statbuf) || (statbuf.st_mode & S_IFMT) == S_IFDIR)
  426.         strcat(zipfn, ZSUFX);
  427.  
  428.     if (stat(zipfn, &statbuf)) {/* try again */
  429.         fprintf(stderr, "error:  can't find zipfile [ %s ]\n", zipfn);
  430.         RETURN(9);              /* 9:  file not found */
  431.     } else
  432.         ziplen = statbuf.st_size;
  433.  
  434.     if (argc != 0) {
  435.         fnv = argv;
  436.         process_all_files = FALSE;
  437.     } else
  438.         process_all_files = TRUE;       /* for speed */
  439.  
  440. /*---------------------------------------------------------------------------
  441.     Okey dokey, we have everything we need to get started.  Let's roll.
  442.   ---------------------------------------------------------------------------*/
  443.  
  444.     inbuf = (byte *) (malloc(INBUFSIZ + 4));    /* 4 extra for hold[] (below) */
  445.     outbuf = (byte *) (malloc(OUTBUFSIZ + 1));  /* 1 extra for string termin. */
  446.     if (aflag)                  /* if need an ascebc scratch, */
  447.         outout = (byte *) (malloc(OUTBUFSIZ));
  448.     else                        /*  allocate it... */
  449.         outout = outbuf;        /*  else just point to outbuf */
  450.  
  451.     if ((inbuf == NULL) || (outbuf == NULL) || (outout == NULL)) {
  452.         fprintf(stderr, "error:  can't allocate unzip buffers\n");
  453.         RETURN(4);              /* 4-8:  insufficient memory */
  454.     }
  455.     hold = &inbuf[INBUFSIZ];    /* to check for boundary-spanning signatures */
  456.  
  457. #ifdef THINK_C
  458.     if (!process_zipfile())
  459.         goto start;
  460. #else
  461.     RETURN(process_zipfile());  /* keep passing errors back... */
  462. #endif
  463.  
  464. }       /* end main() */
  465.  
  466.  
  467.  
  468.  
  469.  
  470. /*********************/
  471. /*  Function usage() */
  472. /*********************/
  473.  
  474. void usage()
  475. {
  476. #ifdef NATIVE
  477.     char *astring = "-a     convert ASCII to native character set";
  478. #else
  479. #ifdef MACOS
  480.     char *astring = "-a     convert to Mac textfile format (CR LF => CR)";
  481. #else
  482. #ifdef DOS_OS2
  483.     char *astring = "-a     convert to DOS & OS/2 textfile format (LF => CR LF)";
  484. #else
  485.     char *astring = "-a     convert to Unix/VMS textfile format (CR LF => LF)";
  486. #endif /* ?DOS_OS2 */
  487. #endif /* ?MACOS */
  488. #endif /* ?NATIVE */
  489.  
  490.  
  491.     fprintf(stderr, "UnZip:  Zipfile Extract %s;  (C) 1989 Samuel H. Smith\n",
  492.                  VERSION);
  493.     fprintf(stderr, "Courtesy of:  S.H.Smith  and  The Tool Shop BBS,  \
  494. (602) 279-2673.\n\n");
  495.     fprintf(stderr, "Versions 3.0 and later brought to you by the fine folks \
  496. at Info-ZIP\n");
  497.     fprintf(stderr, "(Info-ZIP@WSMR-Simtel20.Army.Mil)\n\n");
  498.     fprintf(stderr, "Usage:  unzip [ -xecptlvz[qadoUV] ] file[.zip] [filespec...]\n\
  499.   -x,-e  extract files in archive (default--i.e., this flag is optional)\n\
  500.   -c     extract files to stdout (\"CRT\")\n\
  501.   -p     extract files to stdout and no informational messages (for pipes)\n\
  502.   -t     test files\n\
  503.   -l     list files (short format)\n\
  504.   -v     verbose listing of files\n");
  505.     fprintf(stderr, "\
  506.   -z     display only the archive comment\n\
  507.   -q     perform operations quietly (up to two q's allowed)\n\
  508.   %s\n\
  509.   -d     include directory structure when extracting/listing\n\
  510.   -o     OK to overwrite files without prompting\n\
  511.   -U     don't map filenames to lowercase for selected (uppercase) OS's\n\
  512.   -V     retain file version numbers\n", astring);
  513.  
  514. #ifdef VMS
  515.     fprintf(stderr, "Remember that non-lowercase filespecs must be quoted in \
  516. VMS (e.g., \"Makefile\").\n");
  517. #endif
  518.  
  519. }       /* end function usage() */
  520.  
  521.  
  522.  
  523.  
  524.  
  525. /*******************************/
  526. /*  Function process_zipfile() */
  527. /*******************************/
  528.  
  529. int process_zipfile()
  530. /* return PK-type error code */
  531. {
  532.     int error=0, error_in_archive;
  533.  
  534.  
  535.  
  536. /*---------------------------------------------------------------------------
  537.     Open the zipfile for reading and in BINARY mode to prevent CR/LF trans-
  538.     lation, which would corrupt the bitstreams.  Then find and process the
  539.     central directory; list, extract or test member files as instructed; and
  540.     close the zipfile.
  541.   ---------------------------------------------------------------------------*/
  542.  
  543. #ifdef VMS
  544.     change_zipfile_attributes(0);
  545. #endif
  546.     if (open_input_file())      /* this should never happen, given the */
  547.         return (9);             /*   stat() test in main(), but... */
  548.  
  549.     if (find_end_central_dir()) /* not found; nothing to do */
  550.         return (2);             /* 2:  error in zipfile */
  551.  
  552. #ifdef TEST
  553.     printf("\n  found end-of-central-dir signature at offset %ld (%.8lXh)\n",
  554.       cur_zipfile_bufstart+(inptr-inbuf), cur_zipfile_bufstart+(inptr-inbuf) );
  555.     printf("    from beginning of file; offset %d (%.4Xh) within block\n",
  556.       inptr-inbuf, inptr-inbuf);
  557. #endif
  558.  
  559.     if ((error_in_archive = process_end_central_dir()) > 1)
  560.         return (error_in_archive);
  561.  
  562.     if (zflag)
  563.         return (0);
  564.  
  565. #ifndef PAKFIX
  566.     if (ecrec.number_this_disk == 0) {
  567. #else /* PAKFIX */
  568.     if (ecrec.number_this_disk == 0  ||  (error = (ecrec.number_this_disk == 1
  569.         && ecrec.num_disk_with_start_central_dir == 1))) {
  570.  
  571.         if (error) {
  572.             fprintf(stderr,
  573.      "\n     Warning:  zipfile claims to be disk 2 of a two-part archive;\n\
  574.      attempting to process anyway.  If no further errors occur, this\n\
  575.      archive was probably created by PAK v2.5 or earlier.  This bug\n\
  576.      has been reported to NoGate and should be fixed by mid-April 1991.\n\n");
  577.             error_in_archive = 1;  /* 1:  warning */
  578.         }
  579. #endif /* ?PAKFIX */
  580.         if (vflag)
  581.             error = list_files();       /* LIST 'EM */
  582.         else
  583.             error = extract_or_test_files();    /* EXTRACT OR TEST 'EM */
  584.         if (error > error_in_archive)   /* don't overwrite stronger error */
  585.             error_in_archive = error;   /*  with (for example) a warning */
  586.     } else {
  587.         fprintf(stderr, "\nerror:  zipfile is part of multi-disk archive \
  588. (sorry, no can do).\n");
  589.         fprintf(stderr, ReportMsg);   /* report to info-zip */
  590.         error_in_archive = 11;  /* 11:  no files found */
  591.     }
  592.  
  593.     close(zipfd);
  594. #ifdef VMS
  595.     change_zipfile_attributes(1);
  596. #endif
  597.     return (error_in_archive);
  598.  
  599. }       /* end function process_zipfile() */
  600.  
  601.  
  602.  
  603.  
  604.  
  605. /************************************/
  606. /*  Function find_end_central_dir() */
  607. /************************************/
  608.  
  609. int find_end_central_dir()
  610. /* return 0 if found, 1 otherwise */
  611. {
  612.     int i, numblks;
  613.     longint tail_len;
  614.  
  615.  
  616.  
  617. /*---------------------------------------------------------------------------
  618.     Treat case of short zipfile separately.
  619.   ---------------------------------------------------------------------------*/
  620.  
  621.     if (ziplen <= INBUFSIZ) {
  622.         lseek(zipfd, 0L, SEEK_SET);
  623.         if ((incnt = read(zipfd,inbuf,(unsigned int)ziplen)) == ziplen)
  624.  
  625.             /* 'P' must be at least 22 bytes from end of zipfile */
  626.             for ( inptr = inbuf+ziplen-22  ;  inptr >= inbuf  ;  --inptr )
  627.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  628.                       !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  629.                     incnt -= inptr - inbuf;
  630.                     return(0);  /* found it! */
  631.                 }               /* ...otherwise fall through & fail */
  632.  
  633. /*---------------------------------------------------------------------------
  634.     Zipfile is longer than INBUFSIZ:  may need to loop.  Start with short
  635.     block at end of zipfile (if not TOO short).
  636.   ---------------------------------------------------------------------------*/
  637.  
  638.     } else {
  639.         if ((tail_len = ziplen % INBUFSIZ) > ECREC_SIZE) {
  640.             cur_zipfile_bufstart = lseek(zipfd, ziplen-tail_len, SEEK_SET);
  641.             if ((incnt = read(zipfd,inbuf,(unsigned int)tail_len)) != tail_len)
  642.                 goto fail;      /* shut up, it's expedient. */
  643.  
  644.             /* 'P' must be at least 22 bytes from end of zipfile */
  645.             for ( inptr = inbuf+tail_len-22  ;  inptr >= inbuf  ;  --inptr )
  646.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  647.                       !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  648.                     incnt -= inptr - inbuf;
  649.                     return(0);  /* found it! */
  650.                 }               /* ...otherwise search next block */
  651.             strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  652.                                                            boundary */
  653.  
  654.         } else {
  655.             cur_zipfile_bufstart = ziplen - tail_len;
  656.         }
  657.  
  658.         /*
  659.          * Loop through blocks of zipfile data, starting at the end and going
  660.          * toward the beginning.  Need only check last 65557 bytes of zipfile:
  661.          * comment may be up to 65535 bytes long, end-of-central-directory rec-
  662.          * ord is 18 bytes (shouldn't hardcode this number, but what the hell:
  663.          * already did so above (22=18+4)), and sig itself is 4 bytes.
  664.          */
  665.  
  666.         /*          ==amt to search==   ==done==   ==rounding==     =blksiz= */
  667.         numblks = ( min(ziplen,65557) - tail_len + (INBUFSIZ-1) ) / INBUFSIZ;
  668.  
  669.         for ( i = 1  ;  i <= numblks  ;  ++i ) {
  670.             cur_zipfile_bufstart -= INBUFSIZ;
  671.             lseek(zipfd, cur_zipfile_bufstart, SEEK_SET);
  672.             if ((incnt = read(zipfd,inbuf,INBUFSIZ)) != INBUFSIZ)
  673.                 break;          /* fall through and fail */
  674.  
  675.             for ( inptr = inbuf+INBUFSIZ-1  ;  inptr >= inbuf  ;  --inptr )
  676.                 if ( (ascii_to_native(*inptr) == 'P')  &&
  677.                       !strncmp((char *)inptr, END_CENTRAL_SIG, 4) ) {
  678.                     incnt -= inptr - inbuf;
  679.                     return(0);  /* found it! */
  680.                 }
  681.             strncpy((char *)hold, (char *)inbuf, 3);    /* sig may span block
  682.                                                            boundary */
  683.         }
  684.  
  685.     } /* end if (ziplen > INBUFSIZ) */
  686.  
  687. /*---------------------------------------------------------------------------
  688.     Searched through whole region where signature should be without finding
  689.     it.  Print informational message and die a horrible death.
  690.   ---------------------------------------------------------------------------*/
  691.  
  692. fail:
  693.  
  694.     fprintf(stderr, "\nFile:  %s\n\n\
  695.      End-of-central-directory signature not found.  Either this file is not\n\
  696.      a zipfile, or it constitutes one disk of a multi-part archive.  In the\n\
  697.      latter case the central directory and zipfile comment will be found on\n\
  698.      the last disk(s) of this archive.\n", zipfn);
  699.     return(1);
  700.  
  701. }       /* end function find_end_central_dir() */
  702.  
  703.  
  704.  
  705.  
  706.  
  707. /***************************************/
  708. /*  Function process_end_central_dir() */
  709. /***************************************/
  710.  
  711. int process_end_central_dir()
  712. /* return PK-type error code */
  713. {
  714. #ifdef NOTINT16
  715.     end_central_byte_record byterec;
  716. #endif
  717.     int error=0;
  718.  
  719.  
  720.  
  721. /*---------------------------------------------------------------------------
  722.     Read the end-of-central-directory record and do any necessary machine-
  723.     type conversions (byte ordering, structure padding compensation).
  724.   ---------------------------------------------------------------------------*/
  725.  
  726. #ifndef NOTINT16
  727.     if (readbuf((char *) &ecrec, ECREC_SIZE+4) <= 0)
  728.         return (51);            /* 51:  unexpected EOF */
  729.  
  730. #else  /* NOTINT16:  read data into character array, then copy to struct */
  731.     if (readbuf((char *) byterec, ECREC_SIZE+4) <= 0)
  732.         return (51);
  733.  
  734.     ecrec.number_this_disk =
  735.         makeword(&byterec[NUMBER_THIS_DISK]);
  736.     ecrec.num_disk_with_start_central_dir =
  737.         makeword(&byterec[NUM_DISK_WITH_START_CENTRAL_DIR]);
  738.     ecrec.num_entries_centrl_dir_ths_disk =
  739.         makeword(&byterec[NUM_ENTRIES_CENTRL_DIR_THS_DISK]);
  740.     ecrec.total_entries_central_dir =
  741.         makeword(&byterec[TOTAL_ENTRIES_CENTRAL_DIR]);
  742.     ecrec.size_central_directory =
  743.         makelong(&byterec[SIZE_CENTRAL_DIRECTORY]);
  744.     ecrec.offset_start_central_directory =
  745.         makelong(&byterec[OFFSET_START_CENTRAL_DIRECTORY]);
  746.     ecrec.zipfile_comment_length =
  747.         makeword(&byterec[ZIPFILE_COMMENT_LENGTH]);
  748. #endif  /* NOTINT16 */
  749.  
  750. /*---------------------------------------------------------------------------
  751.     Get the zipfile comment, if any, and print it out.  (Comment may be up
  752.     to 64KB long.  May the fleas of a thousand camels infest the armpits of
  753.     anyone who actually takes advantage of this fact.)  Then position the
  754.     file pointer to the beginning of the central directory and fill buffer.
  755.   ---------------------------------------------------------------------------*/
  756.  
  757.     if (ecrec.zipfile_comment_length && !quietflg) {
  758.         if (!zflag)
  759.           printf("[%s] comment:  ", zipfn);
  760.         if (do_string(ecrec.zipfile_comment_length,DISPLAY)) {
  761.             fprintf(stderr, "\nwarning:  zipfile comment truncated\n");
  762.             error = 1;          /* 1:  warning error */
  763.         }
  764.         if (!zflag)
  765.           printf("\n\n");
  766.     }
  767.     LSEEK( ULONG_(ecrec.offset_start_central_directory) )
  768.  
  769.     return (error);
  770.  
  771. }       /* end function process_end_central_dir() */
  772.  
  773.  
  774.  
  775.  
  776.  
  777. /**************************/
  778. /*  Function list_files() */
  779. /**************************/
  780.  
  781. int list_files()
  782. /* return PK-type error code */
  783. {
  784.     char **fnamev;
  785.     int do_this_file = FALSE, ratio, error, error_in_archive = 0;
  786.     int which_hdr = (vflag > 1);
  787.     UWORD j, yr, mo, dy, hh, mm, members = 0;
  788.     ULONG tot_csize = 0L, tot_ucsize = 0L;
  789.     static char *method[NUM_METHODS + 1] =
  790.     {"Stored", "Shrunk", "Reduce1", "Reduce2",
  791.      "Reduce3", "Reduce4", "Implode", "Unknown"};
  792.     static char *Headers[][2] =
  793.     {
  794.         {" Length    Date    Time    Name",
  795.          " ------    ----    ----    ----"},
  796.         {" Length  Method   Size  Ratio   Date    Time   CRC-32     Name",
  797.          " ------  ------   ----  -----   ----    ----   ------     ----"}};
  798.  
  799.  
  800.  
  801. /*---------------------------------------------------------------------------
  802.     Unlike extract_or_test_files(), this routine confines itself to the cen-
  803.     tral directory.  Thus its structure is somewhat simpler, since we can do
  804.     just a single loop through the entire directory, listing files as we go.
  805.  
  806.     So to start off, print the heading line and then begin main loop through
  807.     the central directory.  The results will look vaguely like the following:
  808.  
  809.   Length  Method   Size  Ratio   Date    Time   CRC-32     Name ("^" ==> case
  810.   ------  ------   ----  -----   ----    ----   ------     ----   conversion)
  811.    44004  Implode  13041  71%  11-02-89  19:34  8b4207f7   Makefile.UNIX
  812.     3438  Shrunk    2209  36%  09-15-90  14:07  a2394fd8  ^dos-file.ext
  813.   ---------------------------------------------------------------------------*/
  814.  
  815.     if (quietflg < 2)
  816.         if (Uflag)
  817.             printf("%s\n%s\n", Headers[which_hdr][0], Headers[which_hdr][1]);
  818.         else
  819.             printf("%s (\"^\" ==> case\n%s   conversion)\n", 
  820.               Headers[which_hdr][0], Headers[which_hdr][1]);
  821.  
  822.     for (j = 0; j < ecrec.total_entries_central_dir; ++j) {
  823.  
  824.         if (readbuf(sig, 4) <= 0)
  825.             return (51);        /* 51:  unexpected EOF */
  826.         if (strncmp(sig, CENTRAL_HDR_SIG, 4)) {  /* just to make sure */
  827.             fprintf(stderr, CentSigMsg, j);  /* sig not found */
  828.             fprintf(stderr, ReportMsg);   /* report to info-zip */
  829.             return (3);         /* 3:  error in zipfile */
  830.         }
  831.         if ((error = process_central_file_header()) != 0)  /* (sets lcflag) */
  832.             return (error);     /* only 51 (EOF) defined */
  833.  
  834.         /*
  835.          * We could DISPLAY the filename instead of storing (and possibly trun-
  836.          * cating, in the case of a very long name) and printing it, but that
  837.          * has the disadvantage of not allowing case conversion--and it's nice
  838.          * to be able to see in the listing precisely how you have to type each
  839.          * filename in order for unzip to consider it a match.  Speaking of
  840.          * which, if member names were specified on the command line, check in
  841.          * with match() to see if the current file is one of them, and make a
  842.          * note of it if it is.
  843.          */
  844.  
  845.         if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  846.             error_in_archive = error;  /* (uses lcflag)---^   */
  847.             if (error > 1)      /* fatal:  can't continue */
  848.                 return (error);
  849.         }
  850.         if ((error = do_string(crec.extra_field_length, SKIP)) != 0) {
  851.             error_in_archive = error;   /* might be just warning */
  852.             if (error > 1)      /* fatal */
  853.                 return (error);
  854.         }
  855.         if (!process_all_files) {   /* check if specified on command line */
  856.             do_this_file = FALSE;
  857.             fnamev = fnv;       /* don't destroy permanent filename ptr */
  858.             for (--fnamev; *++fnamev;)
  859.                 if (match(filename, *fnamev)) {
  860.                     do_this_file = TRUE;
  861.                     break;      /* found match, so stop looping */
  862.                 }
  863.         }
  864.         /*
  865.          * If current file was specified on command line, or if no names were
  866.          * specified, do the listing for this file.  Otherwise, get rid of the
  867.          * file comment and go back for the next file.
  868.          */
  869.  
  870.         if (process_all_files || do_this_file) {
  871.  
  872.             yr = (((crec.last_mod_file_date >> 9) & 0x7f) + 80) % 100;
  873.             mo = (crec.last_mod_file_date >> 5) & 0x0f;
  874.             dy = crec.last_mod_file_date & 0x1f;
  875.             hh = (crec.last_mod_file_time >> 11) & 0x1f;
  876.             mm = (crec.last_mod_file_time >> 5) & 0x3f;
  877.  
  878.             csize = (longint) ULONG_(crec.compressed_size);
  879.             ucsize = (longint) ULONG_(crec.uncompressed_size);
  880.             if (crec.general_purpose_bit_flag & 1)
  881.                 csize -= 12;    /* if encrypted, don't count encrypt hdr */
  882.  
  883.             ratio = (ucsize == 0) ? 0 :   /* .zip can have 0-length members */
  884.                 ((ucsize > 2000000) ?     /* risk signed overflow if mult. */
  885.                 (int) ((ucsize-csize) / (ucsize/1000L)) + 5 :   /* big */
  886.                 (int) ((1000L*(ucsize-csize)) / ucsize) + 5);   /* small */
  887.  
  888.             switch (which_hdr) {
  889.             case 0:             /* short form */
  890.                 printf("%7ld  %02u-%02u-%02u  %02u:%02u  %c%s\n",
  891.                        ucsize, mo, dy, yr, hh, mm, (lcflag?'^':' '), filename);
  892.                 break;
  893.             case 1:             /* verbose */
  894.                 printf(
  895.                   "%7ld  %-7s%7ld %3d%%  %02u-%02u-%02u  %02u:%02u  %08lx  %c%s\n",
  896.                   ucsize, method[methnum], csize, ratio/10, mo, dy, yr, hh, mm,
  897.                   ULONG_(crec.crc32), (lcflag?'^':' '), filename);
  898.             }
  899.  
  900.             error = do_string(crec.file_comment_length, (QCOND2 ? DISPLAY : SKIP));
  901.             if (error) {
  902.                 error_in_archive = error;  /* might be just warning */
  903.                 if (error > 1)  /* fatal */
  904.                     return (error);
  905.             }
  906.             tot_ucsize += (ULONG) ucsize;
  907.             tot_csize += (ULONG) csize;
  908.             ++members;
  909.  
  910.         } else {        /* not listing this file */
  911.             if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
  912.               error_in_archive = error;   /* might be warning */
  913.               if (error > 1)      /* fatal */
  914.                   return (error);
  915.             }
  916.         }
  917.     }                   /* end for-loop (j: files in central directory) */
  918.  
  919. /*---------------------------------------------------------------------------
  920.     Print footer line and totals (compressed size, uncompressed size, number
  921.     of members in zipfile).
  922.   ---------------------------------------------------------------------------*/
  923.  
  924.     ratio = (tot_ucsize == 0) ? 
  925.         0 : ((tot_ucsize > 4000000) ?    /* risk unsigned overflow if mult. */
  926.         (int) ((tot_ucsize - tot_csize) / (tot_ucsize/1000L)) + 5 :
  927.         (int) ((tot_ucsize - tot_csize) * 1000L / tot_ucsize) + 5);
  928.  
  929.     if (quietflg < 2) {
  930.         switch (which_hdr) {
  931.         case 0:         /* short */
  932.             printf("%s\n%7lu                    %-7u\n",
  933.                    " ------                    -------",
  934.                    tot_ucsize, members);
  935.             break;
  936.         case 1:         /* verbose */
  937.             printf(
  938.               "%s\n%7lu         %7lu %3d%%                              %-7u\n",
  939.               " ------          ------  ---                              -------",
  940.               tot_ucsize, tot_csize, ratio / 10, members);
  941.         }
  942.     }
  943. /*---------------------------------------------------------------------------
  944.     Double check that we're back at the end-of-central-directory record.
  945.   ---------------------------------------------------------------------------*/
  946.  
  947.     readbuf(sig, 4);
  948.     if (strncmp(sig, END_CENTRAL_SIG, 4)) {     /* just to make sure again */
  949.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  950.         fprintf(stderr, ReportMsg);  /* report to info-zip */
  951.         error_in_archive = 1;        /* 1:  warning error */
  952.     }
  953.     return (error_in_archive);
  954.  
  955. }       /* end function list_files() */
  956.  
  957.  
  958.  
  959.  
  960.  
  961. /*************************************/
  962. /*  Function extract_or_test_files() */
  963. /*************************************/
  964.  
  965. int extract_or_test_files()
  966. /* return PK-type error code */
  967. {
  968.     char **fnamev;
  969.     byte *cd_inptr;
  970.     int cd_incnt, error, error_in_archive = 0;
  971.     UWORD i, j, members_remaining;
  972.     longint cd_bufstart, bufstart, inbuf_offset;
  973.     struct min_info {
  974.         unsigned f_attr;
  975.         longint offset;
  976.         int lcflag;
  977.     } info[DIR_BLKSIZ];
  978.  
  979.  
  980.  
  981. /*---------------------------------------------------------------------------
  982.     The basic idea of this function is as follows.  Since the central di-
  983.     rectory lies at the end of the zipfile and the member files lie at the
  984.     beginning or middle or wherever, it is not very desirable to simply
  985.     read a central directory entry, jump to the member and extract it, and
  986.     then jump back to the central directory.  In the case of a large zipfile
  987.     this would lead to a whole lot of disk-grinding, especially if each mem-
  988.     ber file is small.  Instead, we read from the central directory the per-
  989.     tinent information for a block of files, then go extract/test the whole
  990.     block.  Thus this routine contains two small(er) loops within a very
  991.     large outer loop:  the first of the small ones reads a block of files
  992.     from the central directory; the second extracts or tests each file; and
  993.     the outer one loops over blocks.  There's some file-pointer positioning
  994.     stuff in between, but that's about it.  Btw, it's because of this jump-
  995.     ing around that we can afford to be lenient if an error occurs in one of
  996.     the member files:  we should still be able to go find the other members,
  997.     since we know the offset of each from the beginning of the zipfile.
  998.  
  999.     Begin main loop over blocks of member files.  We know the entire central
  1000.     directory is on this disk:  we would not have any of this information un-
  1001.     less the end-of-central-directory record was on this disk, and we would
  1002.     not have gotten to this routine unless this is also the disk on which
  1003.     the central directory starts.  In practice, this had better be the ONLY
  1004.     disk in the archive, but maybe someday we'll add multi-disk support.
  1005.   ---------------------------------------------------------------------------*/
  1006.  
  1007.     members_remaining = ecrec.total_entries_central_dir;
  1008.     while (members_remaining) {
  1009.         j = 0;
  1010.  
  1011.         /*
  1012.          * Loop through files in central directory, storing offsets, file
  1013.          * attributes, and case-conversion flags until block size is reached.
  1014.          */
  1015.  
  1016.         while (members_remaining && (j < DIR_BLKSIZ)) {
  1017.             --members_remaining;
  1018.  
  1019.             if (readbuf(sig, 4) <= 0) {
  1020.                 error_in_archive = 51;  /* 51:  unexpected EOF */
  1021.                 members_remaining = 0;  /* ...so no more left to do */
  1022.                 break;
  1023.             }
  1024.             if (strncmp(sig, CENTRAL_HDR_SIG, 4)) {  /* just to make sure */
  1025.                 fprintf(stderr, CentSigMsg, j);  /* sig not found */
  1026.                 fprintf(stderr, ReportMsg);   /* report to info-zip */
  1027.                 error_in_archive = 3;   /* 3:  error in zipfile */
  1028.                 members_remaining = 0;  /* ...so no more left to do */
  1029.                 break;
  1030.             }
  1031.             /* (sets lcflag)-------v  */
  1032.             if ((error = process_central_file_header()) != 0) {
  1033.                 error_in_archive = error;   /* only 51 (EOF) defined */
  1034.                 members_remaining = 0;  /* ...so no more left to do */
  1035.                 break;
  1036.             }
  1037.             if ((error = do_string(crec.filename_length, FILENAME)) != 0) {
  1038.                 if (error > error_in_archive)
  1039.                     error_in_archive = error;
  1040.                 if (error > 1) {  /* fatal:  no more left to do */
  1041.                     fprintf(stderr, FilNamMsg, filename, "central");
  1042.                     members_remaining = 0;
  1043.                     break;
  1044.                 }
  1045.             }
  1046.             if ((error = do_string(crec.extra_field_length, SKIP)) != 0) {
  1047.                 if (error > error_in_archive)
  1048.                     error_in_archive = error;
  1049.                 if (error > 1) {  /* fatal */
  1050.                     fprintf(stderr, ExtFieldMsg, filename, "central");
  1051.                     members_remaining = 0;
  1052.                     break;
  1053.                 }
  1054.             }
  1055.             if ((error = do_string(crec.file_comment_length, SKIP)) != 0) {
  1056.                 if (error > error_in_archive)
  1057.                     error_in_archive = error;
  1058.                 if (error > 1) {  /* fatal */
  1059.                     fprintf(stderr, "\n%s:  bad file comment length\n",
  1060.                             filename);
  1061.                     members_remaining = 0;
  1062.                     break;
  1063.                 }
  1064.             }
  1065.             if (process_all_files) {
  1066.                 if (crec.general_purpose_bit_flag & 1) {
  1067.                     fprintf(stderr, CryptMsg, filename);  /* encrypted: skip */
  1068.                     error_in_archive = 1;       /* 1:  warning error */
  1069.                 } else {
  1070.                     ULONG tmp = ULONG_(crec.external_file_attributes);
  1071.  
  1072.                     switch (hostnum) {
  1073.                         case UNIX_:
  1074.                           info[j].f_attr = tmp >> 16;
  1075.                           break;
  1076.                         case DOS_OS2_FAT_:
  1077.                           tmp = (!(tmp & 1)) << 1;   /* read-only bit */
  1078.                           info[j].f_attr = 0444 | tmp<<6 | tmp<<3 | tmp;
  1079. #ifdef UNIX
  1080.                           umask((int)(tmp = umask(0)));
  1081.                           info[j].f_attr &= ~tmp;
  1082. #endif
  1083.                           break;
  1084.                         case MAC_:
  1085.                           tmp &= 1;   /* read-only bit */
  1086.                           info[j].f_attr = tmp;
  1087.                           break;
  1088.                         default:
  1089.                           info[j].f_attr = 0666;
  1090.                           break;
  1091.                     }
  1092.                     info[j].lcflag = lcflag;
  1093.                     info[j++].offset = (longint)
  1094.                         ULONG_(crec.relative_offset_local_header);
  1095.                 }
  1096.             } else {
  1097.                 fnamev = fnv;   /* don't destroy permanent filename pointer */
  1098.                 for (--fnamev; *++fnamev;)
  1099.                     if (match(filename, *fnamev)) {
  1100.                         if (crec.version_needed_to_extract[0] > UNZIP_VERSION) {
  1101.                             fprintf(stderr, "%s:  requires compatibility with\
  1102.  version %u.%u to extract\n       (this handles %u.%u)--skipping.\n", filename,
  1103.                                 crec.version_needed_to_extract[0] / 10,
  1104.                                 crec.version_needed_to_extract[0] % 10,
  1105.                                 UNZIP_VERSION / 10, UNZIP_VERSION % 10);
  1106.                             error_in_archive = 1;       /* 1:  warning error */
  1107.                         } else if (crec.general_purpose_bit_flag & 1) {
  1108.                             fprintf(stderr, CryptMsg, filename);  /* encrypt */
  1109.                             error_in_archive = 1;       /* 1:  warning error */
  1110.                         } else {
  1111.                             ULONG tmp = ULONG_(crec.external_file_attributes);
  1112.  
  1113.                             switch (hostnum) {
  1114.                                 case UNIX_:
  1115.                                   info[j].f_attr = tmp >> 16;
  1116.                                   break;
  1117.                                 case DOS_OS2_FAT_:
  1118.                                   tmp = (!(tmp & 1)) << 1;  /* read-only bit */
  1119.                                   info[j].f_attr = 0444 | tmp<<6 | tmp<<3 | tmp;
  1120. #ifdef UNIX
  1121.                                   umask((int)(tmp = umask(0)));
  1122.                                   info[j].f_attr &= ~tmp;
  1123. #endif
  1124.                                   break;
  1125.                                 case MAC_:
  1126.                                   tmp &= 1;   /* read-only bit */
  1127.                                   info[j].f_attr = tmp;
  1128.                                   break;
  1129.                                 default:
  1130.                                   info[j].f_attr = 0666;
  1131.                                   break;
  1132.                             }
  1133.                             info[j].lcflag = lcflag;
  1134.                             info[j++].offset = (longint)
  1135.                                 ULONG_(crec.relative_offset_local_header);
  1136.                         }
  1137.                         break;  /* found match for filename, so stop looping */
  1138.  
  1139.                     }   /* end if (match), for-loop (fnamev) */
  1140.             }           /* end if (process_all_files) */
  1141.         }               /* end while-loop (adding files to current block) */
  1142.  
  1143.         /* save position in central directory so can come back later */
  1144.         cd_bufstart = cur_zipfile_bufstart;
  1145.         cd_inptr = inptr;
  1146.         cd_incnt = incnt;
  1147.  
  1148.         /*
  1149.          * Loop through files in block, extracting or testing each one.
  1150.          */
  1151.  
  1152.         for (i = 0; i < j; ++i) {
  1153.             /*
  1154.              * if the target position is not within the current input buffer
  1155.              * (either haven't yet read far enough, or (maybe) skipping back-
  1156.              * ward) skip to the target position and reset readbuf().
  1157.              */
  1158.  
  1159.             /* LSEEK(info[i].offset):  */
  1160.             inbuf_offset = info[i].offset % INBUFSIZ;
  1161.             bufstart = info[i].offset - inbuf_offset;
  1162.  
  1163.             if (bufstart != cur_zipfile_bufstart) {
  1164.                 cur_zipfile_bufstart = lseek(zipfd, bufstart, SEEK_SET);
  1165.                 if ((incnt = read(zipfd,inbuf,INBUFSIZ)) <= 0) {
  1166.                     fprintf(stderr, OffsetMsg, filename, "lseek");
  1167.                     error_in_archive = 3;   /* 3:  error in zipfile, but */
  1168.                     continue;               /*  can still do next file   */
  1169.                 }
  1170.                 inptr = inbuf + inbuf_offset;
  1171.                 incnt -= inbuf_offset;
  1172.             } else {
  1173.                 incnt += (inptr-inbuf) - inbuf_offset;
  1174.                 inptr = inbuf + inbuf_offset;
  1175.             }
  1176.             lcflag = info[i].lcflag;
  1177.             f_attr = info[i].f_attr;
  1178.  
  1179.             /* should be in proper position now, so check for sig */
  1180.             if (readbuf(sig, 4) <= 0) {
  1181.                 fprintf(stderr, OffsetMsg, filename, "EOF");  /* bad offset */
  1182.                 error_in_archive = 3;   /* 3:  error in zipfile */
  1183.                 continue;       /* but can still do next one */
  1184.             }
  1185.             if (strncmp(sig, LOCAL_HDR_SIG, 4)) {
  1186.                 fprintf(stderr, OffsetMsg, filename,
  1187.                         "can't find local header sig");   /* bad offset */
  1188.                 error_in_archive = 3;
  1189.                 continue;
  1190.             }
  1191.             if ((error = process_local_file_header()) != 0) {
  1192.                 fprintf(stderr, "\n%s:  bad local header\n", filename);
  1193.                 error_in_archive = error;       /* only 51 (EOF) defined */
  1194.                 continue;       /* can still do next one */
  1195.             }
  1196.             if ((error = do_string(lrec.filename_length, FILENAME)) != 0) {
  1197.                 if (error > error_in_archive)
  1198.                     error_in_archive = error;
  1199.                 if (error > 1) {
  1200.                     fprintf(stderr, FilNamMsg, filename, "local");
  1201.                     continue;   /* go on to next one */
  1202.                 }
  1203.             }
  1204.             if ((error = do_string(lrec.extra_field_length, SKIP)) != 0) {
  1205.                 if (error > error_in_archive)
  1206.                     error_in_archive = error;
  1207.                 if (error > 1) {
  1208.                     fprintf(stderr, ExtFieldMsg, filename, "local");
  1209.                     continue;   /* go on */
  1210.                 }
  1211.             }
  1212.             if ((error = extract_or_test_member()) != 0)
  1213.                 if (error > error_in_archive)
  1214.                     error_in_archive = error;       /* ...and keep going */
  1215.  
  1216.         }                       /* end for-loop (i:  files in current block) */
  1217.  
  1218.         /*
  1219.          * Jump back to where we were in the central directory, then go and do
  1220.          * the next batch of files.
  1221.          */
  1222.  
  1223.         cur_zipfile_bufstart = lseek(zipfd, cd_bufstart, SEEK_SET);
  1224.         read(zipfd, inbuf, INBUFSIZ);   /* were already there ==> no error */
  1225.         inptr = cd_inptr;
  1226.         incnt = cd_incnt;
  1227.  
  1228. #ifdef TEST
  1229.         printf("\ncd_bufstart = %ld (%.8lXh)\n", cd_bufstart, cd_bufstart);
  1230.         printf("cur_zipfile_bufstart = %ld (%.8lXh)\n", cur_zipfile_bufstart,
  1231.           cur_zipfile_bufstart);
  1232.         printf("inptr-inbuf = %d\n", inptr-inbuf);
  1233.         printf("incnt = %d\n\n", incnt);
  1234. #endif
  1235.  
  1236.     }           /* end while-loop (blocks of files in central directory) */
  1237.  
  1238. /*---------------------------------------------------------------------------
  1239.     Double check that we're back at the end-of-central-directory record, and
  1240.     print quick summary of results, if we were just testing the archive.  We
  1241.     send the summary to stdout so that people doing the testing in the back-
  1242.     ground and redirecting to a file can just do a "tail" on the output file.
  1243.   ---------------------------------------------------------------------------*/
  1244.  
  1245.     readbuf(sig, 4);
  1246.     if (strncmp(sig, END_CENTRAL_SIG, 4)) {     /* just to make sure again */
  1247.         fprintf(stderr, EndSigMsg);  /* didn't find end-of-central-dir sig */
  1248.         fprintf(stderr, ReportMsg);  /* report to info-zip */
  1249.         if (!error_in_archive)       /* don't overwrite stronger error */
  1250.             error_in_archive = 1;    /* 1:  warning error */
  1251.     }
  1252.     if (tflag && (quietflg == 1)) {
  1253.         if (error_in_archive)
  1254.             printf("At least one error was detected in the archive.\n");
  1255.         else if (process_all_files)
  1256.             printf("No errors detected.\n");
  1257.         else
  1258.             printf("No errors detected in the tested files.\n");
  1259.     }
  1260.     return (error_in_archive);
  1261.  
  1262. }       /* end function extract_or_test_files() */
  1263.  
  1264.  
  1265.  
  1266.  
  1267.  
  1268. /**************************************/
  1269. /*  Function extract_or_test_member() */
  1270. /**************************************/
  1271.  
  1272. int extract_or_test_member()
  1273. /* return PK-type error code */
  1274. {
  1275.     int error = 0;
  1276.     UWORD b;
  1277.  
  1278.  
  1279.  
  1280. /*---------------------------------------------------------------------------
  1281.     Initialize variables, buffers, etc.
  1282.   ---------------------------------------------------------------------------*/
  1283.  
  1284.     bits_left = 0;
  1285.     bitbuf = 0;
  1286.     outpos = 0L;
  1287.     outcnt = 0;
  1288.     outptr = outbuf;
  1289.     zipeof = 0;
  1290.     crc32val = 0xFFFFFFFFL;
  1291.  
  1292.     memset(outbuf, 0, OUTBUFSIZ);
  1293.     if (aflag)                  /* if we have a scratchpad, clear it out */
  1294.         memset(outout, 0, OUTBUFSIZ);
  1295.  
  1296.     if (tflag) {
  1297.         if (!quietflg) {
  1298.             fprintf(stdout, "  Testing: %-12s ", filename);
  1299.             fflush(stdout);
  1300.         }
  1301.     } else {
  1302.         if (cflag)              /* output to stdout (copy of it) */
  1303. #ifdef MACOS
  1304.             outfd = 1;
  1305. #else
  1306.             outfd = dup(1);
  1307. #endif
  1308.         else {
  1309.             if ((error = mapped_name()) > 1)  /* member name conversion error */
  1310.                 return (2);     /* 2:  (weak) error in zipfile */
  1311.             if (create_output_file())   /* output to file:  read/write perms */
  1312.                 return (50);    /* 50:  disk full */
  1313.         }
  1314.     }                           /* endif (!tflag) */
  1315.  
  1316. /*---------------------------------------------------------------------------
  1317.     Unpack the file.
  1318.   ---------------------------------------------------------------------------*/
  1319.  
  1320.     switch (lrec.compression_method) {
  1321.  
  1322.     case STORED:
  1323.         if (!tflag && QCOND) {
  1324.             fprintf(stdout, " Extracting: %-12s ", filename);
  1325.             if (cflag)
  1326.                 fprintf(stdout, "\n");
  1327.             fflush(stdout);
  1328.         }
  1329.         while (ReadByte(&b))
  1330.             OUTB(b);
  1331.         break;
  1332.  
  1333.     case SHRUNK:
  1334.         if (!tflag && QCOND) {
  1335.             fprintf(stdout, "UnShrinking: %-12s ", filename);
  1336.             if (cflag)
  1337.                 fprintf(stdout, "\n");
  1338.             fflush(stdout);
  1339.         }
  1340.         unShrink();
  1341.         break;
  1342.  
  1343.     case REDUCED1:
  1344.     case REDUCED2:
  1345.     case REDUCED3:
  1346.     case REDUCED4:
  1347.         if (!tflag && QCOND) {
  1348.             fprintf(stdout, "  Expanding: %-12s ", filename);
  1349.             if (cflag)
  1350.                 fprintf(stdout, "\n");
  1351.             fflush(stdout);
  1352.         }
  1353.         unReduce();
  1354.         break;
  1355.  
  1356.     case IMPLODED:
  1357.         if (!tflag && QCOND) {
  1358.             fprintf(stdout, "  Exploding: %-12s ", filename);
  1359.             if (cflag)
  1360.                 fprintf(stdout, "\n");
  1361.             fflush(stdout);
  1362.         }
  1363.         unImplode();
  1364.         break;
  1365.  
  1366.     default:
  1367.         fprintf(stderr, "%s:  unknown compression method\n", filename);
  1368.         /* close and delete file before return?? */
  1369.         return (1);             /* 1:  warning error */
  1370.     }
  1371.  
  1372. /*---------------------------------------------------------------------------
  1373.     Write the last partial buffer, if any; set the file date and time; and
  1374.     close the file (not necessarily in that order).  Then make sure CRC came
  1375.     out OK and print result.  [Note:  crc32val must be logical-ANDed with
  1376.     32 bits of 1's, or else machines whose longs are bigger than 32 bits will
  1377.     report bad CRCs (because of the upper bits being filled with 1's instead
  1378.     of 0's).]
  1379.   ---------------------------------------------------------------------------*/
  1380.  
  1381.     if (FlushOutput())
  1382.         return (50);            /* 50:  disk full */
  1383.  
  1384.     if (!tflag)
  1385. #if defined(VMS) || defined(MTS)/* VMS already set file time; MTS can't */
  1386.         close(outfd);
  1387. #else
  1388.         set_file_time_and_close();
  1389. #endif
  1390.  
  1391.     if ((crc32val = ((~crc32val) & 0xFFFFFFFFL)) != ULONG_(lrec.crc32)) {
  1392.         /* if quietflg is set we haven't output the filename yet, do it */
  1393.         if (quietflg)
  1394.             printf("%-12s: ", filename);
  1395.         fprintf(stdout, " Bad CRC %08lx  (should be %08lx)\n", crc32val,
  1396.                 ULONG_(lrec.crc32));
  1397.         return (1);             /* 1:  warning error */
  1398.     } else if (tflag) {
  1399.         if (!quietflg)
  1400.             fprintf(stdout, " OK\n");
  1401.     } else {
  1402.         if (QCOND)
  1403.             fprintf(stdout, "\n");
  1404.     }
  1405.  
  1406.     return (error);
  1407.  
  1408. }       /* end function extract_or_test_member() */
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414. /*******************************************/
  1415. /*  Function process_central_file_header() */
  1416. /*******************************************/
  1417.  
  1418. int process_central_file_header()
  1419. /* return PK-type error code */
  1420. {
  1421. #ifdef NOTINT16
  1422.     central_directory_byte_header byterec;
  1423. #endif
  1424.  
  1425.  
  1426.  
  1427. /*---------------------------------------------------------------------------
  1428.     Read the next central directory entry and do any necessary machine-type
  1429.     conversions (byte ordering, structure padding compensation--in the latter
  1430.     case, copy the data from the array into which it was read (byterec) to
  1431.     the usable struct (crec)).
  1432.   ---------------------------------------------------------------------------*/
  1433.  
  1434. #ifndef NOTINT16
  1435.     if (readbuf((char *) &crec, CREC_SIZE) <= 0)
  1436.         return (51);
  1437.  
  1438. #else  /* NOTINT16 */
  1439.     if (readbuf((char *) byterec, CREC_SIZE) <= 0)
  1440.         return (51);            /* 51:  unexpected EOF */
  1441.  
  1442.     crec.version_made_by[0] = byterec[C_VERSION_MADE_BY_0];
  1443.     crec.version_made_by[1] = byterec[C_VERSION_MADE_BY_1];
  1444.     crec.version_needed_to_extract[0] = byterec[C_VERSION_NEEDED_TO_EXTRACT_0];
  1445.     crec.version_needed_to_extract[1] = byterec[C_VERSION_NEEDED_TO_EXTRACT_1];
  1446.  
  1447.     crec.general_purpose_bit_flag =
  1448.         makeword(&byterec[C_GENERAL_PURPOSE_BIT_FLAG]);
  1449.     crec.compression_method =
  1450.         makeword(&byterec[C_COMPRESSION_METHOD]);
  1451.     crec.last_mod_file_time =
  1452.         makeword(&byterec[C_LAST_MOD_FILE_TIME]);
  1453.     crec.last_mod_file_date =
  1454.         makeword(&byterec[C_LAST_MOD_FILE_DATE]);
  1455.     crec.crc32 =
  1456.         makelong(&byterec[C_CRC32]);
  1457.     crec.compressed_size =
  1458.         makelong(&byterec[C_COMPRESSED_SIZE]);
  1459.     crec.uncompressed_size =
  1460.         makelong(&byterec[C_UNCOMPRESSED_SIZE]);
  1461.     crec.filename_length =
  1462.         makeword(&byterec[C_FILENAME_LENGTH]);
  1463.     crec.extra_field_length =
  1464.         makeword(&byterec[C_EXTRA_FIELD_LENGTH]);
  1465.     crec.file_comment_length =
  1466.         makeword(&byterec[C_FILE_COMMENT_LENGTH]);
  1467.     crec.disk_number_start =
  1468.         makeword(&byterec[C_DISK_NUMBER_START]);
  1469.     crec.internal_file_attributes =
  1470.         makeword(&byterec[C_INTERNAL_FILE_ATTRIBUTES]);
  1471.     crec.external_file_attributes =
  1472.         makelong(&byterec[C_EXTERNAL_FILE_ATTRIBUTES]); /* LONG, not word! */
  1473.     crec.relative_offset_local_header =
  1474.         makelong(&byterec[C_RELATIVE_OFFSET_LOCAL_HEADER]);
  1475. #endif  /* NOTINT16 */
  1476.  
  1477.     hostnum = min(crec.version_made_by[1], NUM_HOSTS);
  1478. /*  extnum = min( crec.version_needed_to_extract[1], NUM_HOSTS ); */
  1479.     methnum = min(crec.compression_method, NUM_METHODS);
  1480.  
  1481. /*---------------------------------------------------------------------------
  1482.     Set flag for lowercase conversion of filename, depending on which OS the
  1483.     file is coming from.  This section could be ifdef'd if some people have
  1484.     come to love DOS uppercase filenames under Unix...but really, guys, get
  1485.     a life. :)  NOTE THAT ALL SYSTEM NAMES NOW HAVE TRAILING UNDERSCORES!!!
  1486.     This is to prevent interference with compiler command-line defines such
  1487.     as -DUNIX, for example, which are then used in "#ifdef UNIX" constructs.
  1488.   ---------------------------------------------------------------------------*/
  1489.  
  1490.     lcflag = FALSE;
  1491.     if (!Uflag)                 /* as long as user hasn't specified
  1492.                                  * case-preservation */
  1493.         switch (hostnum) {
  1494.         case DOS_OS2_FAT_:
  1495.         case VMS_:
  1496.         case VM_CMS_:           /* all caps? */
  1497.         case CPM_:              /* like DOS, right? */
  1498. /*      case ATARI_:            ??? */
  1499. /*      case Z_SYSTEM_:         ??? */
  1500. /*      case TOPS20_:           (if we had such a thing...) */
  1501.  
  1502.             lcflag = TRUE;      /* convert filename to lowercase */
  1503.             break;
  1504.  
  1505.         default:                /* AMIGA_, UNIX_, (ATARI_), OS2_HPFS_, */
  1506.             break;              /*   MAC_, (Z_SYSTEM_):  no conversion */
  1507.         }
  1508.  
  1509.     return (0);
  1510.  
  1511. }       /* end function process_central_file_header() */
  1512.  
  1513.  
  1514.  
  1515.  
  1516.  
  1517. /*****************************************/
  1518. /*  Function process_local_file_header() */
  1519. /*****************************************/
  1520.  
  1521. int process_local_file_header()
  1522. /* return PK-type error code */
  1523. {
  1524. #ifdef NOTINT16
  1525.     local_byte_header byterec;
  1526. #endif
  1527.  
  1528.  
  1529.  
  1530. /*---------------------------------------------------------------------------
  1531.     Read the next local file header and do any necessary machine-type con-
  1532.     versions (byte ordering, structure padding compensation--in the latter
  1533.     case, copy the data from the array into which it was read (byterec) to
  1534.     the usable struct (lrec)).
  1535.   ---------------------------------------------------------------------------*/
  1536.  
  1537. #ifndef NOTINT16
  1538.     if (readbuf((char *) &lrec, LREC_SIZE) <= 0)
  1539.         return (51);
  1540.  
  1541. #else /* NOTINT16 */
  1542.     if (readbuf((char *) byterec, LREC_SIZE) <= 0)
  1543.         return (51);            /* 51:  unexpected EOF */
  1544.  
  1545.     lrec.version_needed_to_extract[0] = byterec[L_VERSION_NEEDED_TO_EXTRACT_0];
  1546.     lrec.version_needed_to_extract[1] = byterec[L_VERSION_NEEDED_TO_EXTRACT_1];
  1547.  
  1548.     lrec.general_purpose_bit_flag = makeword(&byterec[L_GENERAL_PURPOSE_BIT_FLAG]);
  1549.     lrec.compression_method = makeword(&byterec[L_COMPRESSION_METHOD]);
  1550.     lrec.last_mod_file_time = makeword(&byterec[L_LAST_MOD_FILE_TIME]);
  1551.     lrec.last_mod_file_date = makeword(&byterec[L_LAST_MOD_FILE_DATE]);
  1552.     lrec.crc32 = makelong(&byterec[L_CRC32]);
  1553.     lrec.compressed_size = makelong(&byterec[L_COMPRESSED_SIZE]);
  1554.     lrec.uncompressed_size = makelong(&byterec[L_UNCOMPRESSED_SIZE]);
  1555.     lrec.filename_length = makeword(&byterec[L_FILENAME_LENGTH]);
  1556.     lrec.extra_field_length = makeword(&byterec[L_EXTRA_FIELD_LENGTH]);
  1557. #endif  /* NOTINT16 */
  1558.  
  1559.     csize = (longint) ULONG_(lrec.compressed_size);
  1560.     ucsize = (longint) ULONG_(lrec.uncompressed_size);
  1561.  
  1562.     return (0);                 /* 0:  no error */
  1563.  
  1564. }       /* end function process_local_file_header() */
  1565.